package com.lanzhou.yuanfen.security.session;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.lanzhou.yuanfen.security.MyUserDetails;
import com.lanzhou.yuanfen.security.SocialDetails;
import com.lanzhou.yuanfen.security.token.EmailAuthenticationToken;
import com.lanzhou.yuanfen.security.token.QQAuthenticationToken;
import com.lanzhou.yuanfen.sys.entity.User;
import com.lanzhou.yuanfen.sys.mapper.RolePermissionMapper;
import com.lanzhou.yuanfen.sys.mapper.UserMapper;
import org.springframework.security.authentication.RememberMeAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.List;

/**
 * 授权Service
 *
 * @author Administrator
 */
@Component
public class GrantedAuthorityService {

    @Resource
    private RolePermissionMapper rolePermissionMapper;

    @Resource
    private UserMapper userMapper;


    /**
     * 重新加载(自己的)用户的权限: 加个判断: 社交登入绑定账号后需要给他们添加权限到全局权限管理列表
     * 本质替换 SPRING_SECURITY_CONTEXT -> 内部的: Authentication => HttpSession 中的权限并没有被替换
     *
     * @param session 当前请求的Session
     * @param userKey 用户ID
     */
    public void reloadUserAuthority(HttpSession session, Long userKey) {
        // 新的权限
        List<SimpleGrantedAuthority> authorityList = getGrantedAuthority(userKey);
        Authentication result = null;
        SecurityContext securityContext = (SecurityContext) session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
        Authentication authentication = securityContext.getAuthentication();
        // 这里QQ[社交]登入和其它登入不一样, 需要传入的是SocialDetails
        if (authentication instanceof QQAuthenticationToken) {
            QQAuthenticationToken token = (QQAuthenticationToken) authentication;
            String accessToken = token.getAccessToken();
            String openId = token.getOpenId();
            // 重新new一个token，因为Authentication中的权限是不可变的.
            User user = userMapper.selectUserByOpenId(openId);
            // 有用户的话加入用户信息, 没有的话就采用社交登入Social, 之后绑定用户的时候修改Session的用户权限
            UserDetails principal = user != null ? new MyUserDetails(user, authorityList)
                    : new SocialDetails(openId, authorityList);
            result = new QQAuthenticationToken(accessToken, openId, principal, authorityList);
        } else if (authentication instanceof EmailAuthenticationToken) {
            String email = ((EmailAuthenticationToken) authentication).getEmail();
            String eCode = ((EmailAuthenticationToken) authentication).geteCode();
            User user = userMapper.selectOne(new QueryWrapper<User>().eq("email", email));
            MyUserDetails principal = new MyUserDetails(user, authorityList);
            result = new EmailAuthenticationToken(email, eCode, principal, authorityList);
        } else if (authentication instanceof UsernamePasswordAuthenticationToken) {
            String username = authentication.getName();
            User user = userMapper.selectOne(new QueryWrapper<User>().eq("username", username));
            // 重新new一个token，因为Authentication中的权限是不可变的.
            MyUserDetails principal = new MyUserDetails(user, authorityList);
            UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
                    principal, authentication.getCredentials(),
                    principal.getAuthorities());
            token.setDetails(authentication.getDetails());
            result = token;
        } else if (authentication instanceof RememberMeAuthenticationToken) {
            String username = authentication.getName();
            User user = userMapper.selectOne(new QueryWrapper<User>().eq("username", username));
            // 重新new一个token，因为Authentication中的权限是不可变的.
            MyUserDetails principal = new MyUserDetails(user, authorityList);
            RememberMeAuthenticationToken token = new RememberMeAuthenticationToken(username,
                    principal, principal.getAuthorities());
            token.setDetails(authentication.getDetails());
            result = token;
        }
        securityContext.setAuthentication(result);
    }

    // 下面这句还会触发默认的 SessionListener.attributeReplaced 属性替换, 思考后选择策略
    // session.setAttribute(SessionListener.SPRING_SECURITY_CONTEXT, new SecurityContextImpl(result));

    private List<SimpleGrantedAuthority> getGrantedAuthority(Long userKey) {
        List<SimpleGrantedAuthority> grantedAuthoritySet = new ArrayList<>();
        List<String> perms = rolePermissionMapper.getPermByUserKey(userKey);
        for (String perm : perms) {
            SimpleGrantedAuthority authority = new SimpleGrantedAuthority(perm);
            grantedAuthoritySet.add(authority);
        }
        return grantedAuthoritySet;
    }

}
